#include "Platforms.h"
#ifdef _WIN32
#include "ESContext.h"
#include <vld.h>
#endif

#ifdef _ANDROID
#include <jni.h>
#endif
#include "Shader.h"
#include "Vertex.h"
#include "Timer.h"
#include "Matrix.h"
#include "Camera.h"
#include "TGA.h"
#include "Texture.h"
#include "Model.h"
#include "Object.h"
#include <stdio.h>

#include "ResourceManager.h"
#include "SceneManager.h"
#include "FileManager.h"
#include "InputManager.h"
#include "FrameBuffer.h"
#include "ScreenResolution.h"

ResourceManager *resourceManager = NULL;
SceneManager *sceneManager = NULL;
Camera *camera = NULL;
FileManager *fileManager = NULL;
InputManager *inputManager = NULL;
ScreenResolution *screenResolution = ScreenResolution::GetInstance();
int screenH;

FrameBuffer *frameBuffer = NULL;
union ColorRGBA
{
	int colorValue;
	struct
	{
		unsigned char r, g, b, a;
	};
};

ColorRGBA gColorI;

void Init()
{
	fileManager = FileManager::GetInstance();
	#ifdef _WIN32
	fileManager->Init("../Resources/");
	#endif
	#ifdef _ANDROID
	fileManager->Init("sdcard/Resources/");
	#endif

	resourceManager = ResourceManager::GetInstance();
	resourceManager->Init("Manager/ResourceManager.txt");

	sceneManager = SceneManager::GetInstance();
	sceneManager->Init("Manager/SceneManager.txt");

	inputManager = InputManager::GetInstance();

	camera = sceneManager->GetCameraPointer();

	frameBuffer = new FrameBuffer();
	frameBuffer->Init();

	int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if (status == GL_FRAMEBUFFER_COMPLETE)
	{
		LOGI("FrameBuffer OK\n");
	}
	else
	{
		LOGI("FrameBuffer is not OK\n");
	}

	screenH = screenResolution->GetScreenHeight();
}

void Update()
{
	//LOGI("\nFrame time: %f (s)", Timer::FrameTime() );
	sceneManager->Update();
}

GLubyte color[4];

void Draw()
{
	//sceneManager->Draw();

	//====================
	glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->GetFboId());
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	sceneManager->DrawSelection();

	if (inputManager->IsMouseDown())
	{
		glReadPixels(inputManager->GetXmouse(), screenH - inputManager->GetYmouse(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
		LOGI("%d %d %d %d\n", color[0], color[1], color[2], color[3]);
		gColorI.r = color[0];
		gColorI.g = color[1];
		gColorI.b = color[2];
		//gColorI.a = color[3];
		gColorI.a = 0;
		sceneManager->GetObjectIdByIndex(gColorI.colorValue);
	}

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	sceneManager->Draw();
}

void Destroy()
{
	SceneManager::Destroy();
	ResourceManager::Destroy();
	FileManager::Destroy();
	InputManager::Destroy();
	ScreenResolution::Destroy();

	delete frameBuffer;
}

void Key(int keyCode, bool isKeyDown)
{
	inputManager->OnKey(keyCode, isKeyDown);
}

void Mouse(int type, int x, int y)
{
	inputManager->OnMouse(type, x, y);
	//LOGI("\nMouse type: %d - (x = %d, y = %d)", type, x, y);
}

#ifdef _WIN32
int main()
{	
	screenResolution->Init(SCREEN_W, SCREEN_H);
	InitWindow(screenResolution->GetScreenWitdh(), 
		screenResolution->GetScreenHeight());
	
	RegisterInitFunc(Init);
	RegisterDrawFunc(Draw);
	RegisterUpdateFunc(Update);	
	RegisterDestroyFunc(Destroy);
	RegisterKeyFunc(Key);

	RegisterMouseFunc(Mouse);
	
	WinLoop();
	return 0;
}
#endif

#ifdef _ANDROID
static void printGLString(const char *name, GLenum s) {
    const char *v = (const char *) glGetString(s);
    LOGI("GL %s = %s\n", name, v);
}
static void checkGlError(const char* op) {
    for (GLint error = glGetError(); error; error
            = glGetError()) {
        LOGI("after %s() glError (0x%x)\n", op, error);
    }
}

bool setupGraphics(int w, int h) {
    printGLString("Version", GL_VERSION);
    printGLString("Vendor", GL_VENDOR);
    printGLString("Renderer", GL_RENDERER);
    printGLString("Extensions", GL_EXTENSIONS);

	LOGI("Init viewport %d x %d\n", w, h);
    glViewport(0, 0, w, h);
    checkGlError("glViewport");
    return true;
}


extern "C" {
    JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height);
    JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);
	JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_mouse(JNIEnv * env, jobject obj, jint type, jint x, jint y);
	JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_key(JNIEnv * env, jobject obj, jint keyCode, jboolean isKeyDown);
};

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)
{
    setupGraphics(width, height);
	screenResolution->Init(width, height);
	Init();
}

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
{
	Timer::Tick();
	Update();
    Draw();
}

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_mouse(JNIEnv * env, jobject obj, jint type, jint x, jint y)
{
	Mouse(type, x, y);
}

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_key(JNIEnv * env, jobject obj, jint keyCode, jboolean isKeyDown)
{
	Key(keyCode, isKeyDown);
}
#endif